package com.lyf.scm.plan.domain.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.lyf.scm.common.constants.CommonConstants;
import com.lyf.scm.common.enums.OtherTargetsEnum;
import com.lyf.scm.common.util.ChannelUtil;
import com.lyf.scm.plan.api.dto.*;
import com.lyf.scm.plan.domain.remote.bigdata.dto.OlapMetadataDTO;
import com.lyf.scm.plan.domain.remote.bigdata.dto.OlapQueryResultDTO;
import com.lyf.scm.plan.domain.remote.nateWork.dto.SalesNetworkAnalysisDTO;
import com.lyf.scm.plan.domain.remote.nateWork.facade.NateWorkFacade;
import com.lyf.scm.plan.domain.service.ActualSalesQtyService;
import com.lyf.scm.plan.domain.service.CommonService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.lyf.scm.common.constants.CommonConstants.CATEGORY_LEVEL_FOUR;

/**
 * 实际销量服务
 * 解析从大数据查询的实际销量返回计划模块需要的结构
 *
 * @author Martin
 * @date 2020-11-11 10:00
 */
@Slf4j
@Service
public class ActualSalesQtyServiceImpl implements ActualSalesQtyService {

    @Resource
    private CommonService commonService;
    @Resource
    private NateWorkFacade nateWorkFacade;

    /**
     * 获取列表结果
     *
     * @param otherTargetGeneralQueryDTO
     * @return {@link OtherTargetResultDTO}
     **/
    @Override
    public OtherTargetResultDTO getResult(OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO,Map<String, BigDecimal> unitMap) {
        Map<String, List<BigDecimal>> map = getActualDalesData(this.getQuery(otherTargetGeneralQueryDTO));
        OtherTargetResultDTO otherTargetResultDTO = new OtherTargetResultDTO();
        otherTargetResultDTO.setOtherTargetsEnum(OtherTargetsEnum.ACTUAL_SALES);
        otherTargetResultDTO.setResult(map);
        return otherTargetResultDTO;

    }

    @Override
    public List<OtherTargetResultDTO> getBatchResult(OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO,Map<String, BigDecimal> unitMap) {
        return null;
    }

    /**
     * 获取图表结果
     *
     * @param otherTargetGeneralQueryDTO
     * @return {@link OtherTargetEchartResultDTO}
     **/
    @Override
    public OtherTargetEchartResultDTO getEchartResult(OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO) {
        List<BigDecimal> targetList = getEchartActualDalesData(this.getQuery(otherTargetGeneralQueryDTO));
        OtherTargetEchartResultDTO resultEntity = new OtherTargetEchartResultDTO();
        resultEntity.setOtherTargetsEnum(OtherTargetsEnum.ACTUAL_SALES);
        resultEntity.setResult(targetList);
        return resultEntity;
    }

    @Override
    public List<OtherTargetEchartResultDTO> getBatchEchartResult(OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO) {
        return null;
    }

    private ActualSalesQtyQueryDTO getQuery(OtherTargetGeneralQueryDTO queryData) {
        ActualSalesQtyQueryDTO actualSalesQtyQueryDTO = new ActualSalesQtyQueryDTO();
        List<String> dateList = queryData.getDateList();
        actualSalesQtyQueryDTO.setStartTime(dateList.get(0).replace("-", ""));
        actualSalesQtyQueryDTO.setEndTime(DateUtil.format(DateUtil.offset(DateUtil.parse(dateList.get(dateList.size() - 1), DatePattern.NORM_DATE_PATTERN), DateField.WEEK_OF_MONTH, 1), DatePattern.NORM_DATE_PATTERN).replace("-", ""));

        // 根据仓解析获取销售网络
        if (CollectionUtils.isNotEmpty(queryData.getDeliverIds())) {
            List<SalesNetworkAnalysisDTO> salesNetworkAnalysisList = nateWorkFacade.queryOutBoundByWarehous(queryData.getDeliverIds());
            // 销售网络不为空，取渠道和区域交集
            if (CollectionUtils.isNotEmpty(salesNetworkAnalysisList)) {
                getIntersection(queryData, salesNetworkAnalysisList);
            }
        }

        actualSalesQtyQueryDTO.setKpChannelList(queryData.getChannelList());

        if (queryData.getAreaLevel() != null && CollectionUtils.isNotEmpty(queryData.getAreaCodes())) {
            actualSalesQtyQueryDTO.setAreaAggsLevel(queryData.getAreaLevel());
            ActualSalesQtyQueryDTO.AreaCondition areaCondition = new ActualSalesQtyQueryDTO.AreaCondition(actualSalesQtyQueryDTO.getAreaAggsLevel(), queryData.getAreaCodes());
            actualSalesQtyQueryDTO.setAreaConditionList(Collections.singletonList(areaCondition));
        }
        if (!CollectionUtils.isEmpty(queryData.getSkuList())) {
            ActualSalesQtyQueryDTO.CategoryCondition categoryCondition = new ActualSalesQtyQueryDTO.CategoryCondition(CATEGORY_LEVEL_FOUR, queryData.getSkuList());
            actualSalesQtyQueryDTO.setCategoryConditionList(Collections.singletonList(categoryCondition));
            actualSalesQtyQueryDTO.setSkuList(queryData.getSkuList());
        }
        actualSalesQtyQueryDTO.setDateList(queryData.getDateList());
        return actualSalesQtyQueryDTO;
    }

    private void getIntersection(OtherTargetGeneralQueryDTO queryData, List<SalesNetworkAnalysisDTO> salesNetworkAnalysisList) {
        List<String> channelCodeList = null;
        if (CollectionUtils.isNotEmpty(queryData.getChannelList())) {
            channelCodeList = queryData.getChannelList().stream().filter(val ->
                    salesNetworkAnalysisList.stream()
                            .anyMatch(res -> res.getChannelCode().equals(val))).distinct().collect(Collectors.toList());
        }

        List<String> areaList = null;
        if (CollectionUtils.isNotEmpty(queryData.getAreaCodes())) {
            Integer areaLevel = queryData.getAreaLevel();
            areaList = queryData.getAreaCodes().stream().filter(val ->
                    salesNetworkAnalysisList.stream().anyMatch(res -> {
                        switch (areaLevel) {
                            case 1:
                                return val.equals(res.getProvinceCode());
                            case 2:
                                return val.equals(res.getCityCode());
                            case 3:
                                return val.equals(res.getCounty());
                            default:
                                return false;
                        }
                    })).distinct().collect(Collectors.toList());
        }
        queryData.setChannelList(channelCodeList);
        queryData.setAreaCodes(areaList);
    }

    @Override
    public Map<String, List<BigDecimal>> getActualDalesData(ActualSalesQtyQueryDTO queryDTO) {
        try {
            if (queryDTO == null || StringUtils.isEmpty(queryDTO.getStartTime())
                    || StringUtils.isEmpty(queryDTO.getEndTime()) || queryDTO.getAreaConditionList() == null
                    || queryDTO.getSkuList() == null || queryDTO.getKpChannelList() == null) {
                return null;
            }
            // 查询入参
            OlapMetadataDTO dto = new OlapMetadataDTO();
            // 日期条件
            dto.setStartTime(queryDTO.getStartTime());
            dto.setEndTime(queryDTO.getEndTime());
            // 分组列
            List<String> olapColumnList = new ArrayList<>();
            olapColumnList.add(OlapQueryResultDTO.OlapGroupColumnEnum.CHANNEL.getOlapCode());
            if (queryDTO.getAreaAggsLevel().equals(CommonConstants.ONE)) {
                olapColumnList.add(OlapQueryResultDTO.OlapGroupColumnEnum.PROVINCE.getOlapCode());
            } else if (queryDTO.getAreaAggsLevel().equals(CommonConstants.TWO)) {
                olapColumnList.add(OlapQueryResultDTO.OlapGroupColumnEnum.CITY.getOlapCode());
            } else if (queryDTO.getAreaAggsLevel().equals(CommonConstants.THREE)) {
                olapColumnList.add(OlapQueryResultDTO.OlapGroupColumnEnum.COUNTY.getOlapCode());
            } else {
                olapColumnList.add(OlapQueryResultDTO.OlapGroupColumnEnum.NODE_ID.getOlapCode());
            }
            olapColumnList.add(OlapQueryResultDTO.OlapGroupColumnEnum.SKU_KEY.getOlapCode());
            olapColumnList.add(OlapQueryResultDTO.OlapGroupColumnEnum.WEEK.getOlapCode());
            dto.setDimensions(olapColumnList);
            Map<String, List<String>> map = new HashMap<>();
            // 渠道条件
            List<String> bigdataChannelList = queryDTO.getKpChannelList().stream()
                    .map(ChannelUtil::getBigdataChannel).collect(Collectors.toList());
            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.CHANNEL.getOlapCode(), bigdataChannelList);
            // 品类和sku条件，只取sku
            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.SKU_KEY.getOlapCode(), queryDTO.getSkuList());
            // 区域条件
            List<ActualSalesQtyQueryDTO.AreaCondition> areaConditionList = queryDTO.getAreaConditionList();
            for (ActualSalesQtyQueryDTO.AreaCondition areaCondition : areaConditionList) {
                switch (queryDTO.getAreaAggsLevel()) {
                    case 1:
                        map.put(OlapQueryResultDTO.OlapGroupColumnEnum.PROVINCE.getOlapCode(), areaCondition.getList());
                        break;
                    case 2:
                        map.put(OlapQueryResultDTO.OlapGroupColumnEnum.CITY.getOlapCode(), areaCondition.getList());
                        break;
                    case 4:
                        map.put(OlapQueryResultDTO.OlapGroupColumnEnum.NODE_ID.getOlapCode(), areaCondition.getList());
                        break;
                    default:
                        break;
                }
            }
            dto.setFilter(Collections.singletonList(map));
            try {
                long start = System.currentTimeMillis();
                OlapQueryResultDTO olapQueryResultDTO = commonService.queryMultiDimensional(dto);
                long end = System.currentTimeMillis();
                log.info("getActualSalesQtyGroupByChannelAreaSku调大数据查询实际销量耗时：{}ms", (end - start));
                return this.parseData(queryDTO, olapQueryResultDTO);
            } catch (Exception e) {
                log.error("查询大数据查询实际销量失败，原因：{}", e.getMessage());
                return this.parseNullData(queryDTO);
            }
        } catch (Exception e) {
            log.error("获取实际销量异常：", e);
        }
        return null;
    }

    private Map<String, List<BigDecimal>> parseNullData(ActualSalesQtyQueryDTO queryDTO) {
        return null;
    }

    @Override
    public List<BigDecimal> getEchartActualDalesData(ActualSalesQtyQueryDTO queryDTO) {
        try {
            if (queryDTO == null || StringUtils.isEmpty(queryDTO.getStartTime())
                    || StringUtils.isEmpty(queryDTO.getEndTime())) {
                return null;
            }
            // 查询入参
            OlapMetadataDTO dto = new OlapMetadataDTO();
            // 日期条件
            dto.setStartTime(queryDTO.getStartTime());
            dto.setEndTime(queryDTO.getEndTime());
            // 分组列
            dto.setDimensions(Arrays.asList(OlapQueryResultDTO.OlapGroupColumnEnum.WEEK.getOlapCode()));
            Map<String, List<String>> map = new HashMap<>();
            // 渠道条件
            if (queryDTO.getKpChannelList() != null && queryDTO.getKpChannelList().size() > 0) {
                List<String> bigdataChannelList = queryDTO.getKpChannelList().stream()
                        .map(ChannelUtil::getBigdataChannel).collect(Collectors.toList());
                map.put(OlapQueryResultDTO.OlapGroupColumnEnum.CHANNEL.getOlapCode(), bigdataChannelList);
            }
            // 品类条件
            if (queryDTO.getCategoryConditionList() != null && queryDTO.getCategoryConditionList().size() > 0) {
                List<ActualSalesQtyQueryDTO.CategoryCondition> categoryConditionList = queryDTO.getCategoryConditionList();
                for (ActualSalesQtyQueryDTO.CategoryCondition categoryCondition : categoryConditionList) {
                    List<String> list = categoryCondition.getList();
                    switch (categoryCondition.getLevel()) {
                        case 2:
                            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.CATEGORY_2.getOlapCode(), list);
                            break;
                        case 3:
                            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.CATEGORY_3.getOlapCode(), list);
                            break;
                        case 4:
                            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.CATEGORY_4.getOlapCode(), list);
                            break;
                        default:
                            break;
                    }
                }
            }
            //sku条件
            if (queryDTO.getSkuList() != null && queryDTO.getSkuList().size() > 0) {
                map.put(OlapQueryResultDTO.OlapGroupColumnEnum.SKU_KEY.getOlapCode(), queryDTO.getSkuList());
            }
            // 区域条件
            if (queryDTO.getAreaConditionList() != null && queryDTO.getAreaConditionList().size() > 0) {

                List<ActualSalesQtyQueryDTO.AreaCondition> areaConditionList = queryDTO.getAreaConditionList();
                for (ActualSalesQtyQueryDTO.AreaCondition areaCondition : areaConditionList) {
                    switch (areaCondition.getLevel()) {
                        case 1:
                            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.PROVINCE.getOlapCode(), areaCondition.getList());
                            break;
                        case 2:
                            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.CITY.getOlapCode(), areaCondition.getList());
                            break;
                        case 4:
                            map.put(OlapQueryResultDTO.OlapGroupColumnEnum.NODE_ID.getOlapCode(), areaCondition.getList());
                            break;
                        default:
                            break;
                    }
                }
            }
            dto.setFilter(Collections.singletonList(map));
            long start = System.currentTimeMillis();
            OlapQueryResultDTO olapQueryResultDTO = null;
            try {
                olapQueryResultDTO = commonService.queryMultiDimensional(dto);
                long end = System.currentTimeMillis();
                log.info("groupByDate调大数据查询实际销量耗时：{}ms", (end - start));
                return this.parseEchartData(queryDTO, olapQueryResultDTO);
            } catch (Exception e) {
                log.error("查询大数据查询实际销量失败，原因：{}", e.getMessage());
                return this.parseEchartNullData(queryDTO);
            }
        } catch (Exception e) {
            log.error("获取实际销量异常：", e);
        }
        return null;
    }

    private List<BigDecimal> parseEchartNullData(ActualSalesQtyQueryDTO queryDTO) {
        List<BigDecimal> targetList = new ArrayList<>();
        queryDTO.getDateList().forEach(v -> targetList.add(BigDecimal.ZERO));
        return targetList;
    }

    /**
     * @param queryData  入参
     * @param resultData 需要解析的数据
     * @return
     */
    private Map<String, List<BigDecimal>> parseData(ActualSalesQtyQueryDTO queryData, OlapQueryResultDTO resultData) {
        Map<String, List<BigDecimal>> resultMap = new HashMap<>();
        if (resultData == null) {
            return parseNullData(queryData);
        }
        List<List<Object>> rows = resultData.getRows();
        for (List<Object> row : rows) {
            int size = row.size();
            StringBuilder key = new StringBuilder();
            for (int i = 1; i < size - 1; i++) {
                key.append(row.get(i));
            }

            String date = row.get(size - 1).toString();
            date = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd")).with(DayOfWeek.MONDAY).toString();
            List<BigDecimal> targetList = new ArrayList<>();
            for (String val : queryData.getDateList()) {
                targetList.add(date.equals(val) ? new BigDecimal(row.get(0).toString()) : BigDecimal.ZERO);
            }
            resultMap.put(key.toString(), targetList);
        }
        return resultMap;
    }

    /**
     * @param queryData  入参
     * @param resultData 需要解析的数据
     * @return
     */
    private List<BigDecimal> parseEchartData(ActualSalesQtyQueryDTO queryData, OlapQueryResultDTO resultData) {
        // 定义返回结果集
        List<BigDecimal> resultList = new ArrayList<>();
        if (resultData == null) {
            return this.parseEchartNullData(queryData);
        }
        // 每个周周一的日期集合
        List<String> dateList = queryData.getDateList();
        // 查询结果集[[值,日期],[值，日期],[值，日期]]
        List<List<Object>> dataRows = resultData.getRows();
        for (String date : dateList) {
            resultList.add(
                    // 取查询结果集中日期的周一，与日期集合中的值相等则相加
                    dataRows.stream().filter(objList -> {
                        String resultDate = LocalDate.parse(objList.get(1).toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd"))
                                .with(DayOfWeek.MONDAY).toString();
                        return resultDate.equals(date);
                    })
                            .map(val -> {
                                String targetQty = val.get(0).toString();
                                return targetQty == null ? BigDecimal.ZERO : new BigDecimal(targetQty);
                            })
                            .reduce(BigDecimal.ZERO, BigDecimal::add)
            );
        }
        return resultList;
    }


    /**
     * demo:
     *         ActualSalesQtyQueryDTO dto = new ActualSalesQtyQueryDTO();
     *         dto.setAreaCondition(new ActualSalesQtyQueryDTO.AreaCondition(1, Arrays.asList("310000", "320000")));
     *         dto.setSkuList(Arrays.asList("14884", "10024", "11442", "11441"));
     *         dto.setDateList(Arrays.asList("2020-10-19", "2020-10-26", "2020-11-02", "2020-11-09", "2020-11-16"));
     *         dto.setStartTime("20201019");
     *         dto.setEndTime("20201122");
     *         dto.setKpChannelList(Arrays.asList("C00001"));
     *         Map<String, List<BigDecimal>> res = actualSalesQtyService.getActualSalesQtyGroupByChannelAreaSku(dto);
     */

}
